#ifndef __DLMALLOC_H_INCLUDED__
#define __DLMALLOC_H_INCLUDED__

// Little hack :
// on most platforms, mallinfo is not defined, so we define it here.
// Problem : on Android (for instance, I guess that on Linux it's the same)
// malloc.h is included and has a definition of mallinfo, so this causes a
// conflict. This is why we only define it if _MALLOC_H_ is not already
// defined. If we check for GLT_PLATFORM_ANDROID, the problem will still
// happen if we include dlmalloc.h in Glitch or anywhere else. And we can't
// check for GLITCH_PLATFORM_ANDROID here ...
#if defined(__QNX__)
#    include <malloc.h>
#elif !NO_MALLINFO && !defined(_MALLOC_H_) && !__linux && !__CYGWIN__
#    define STRUCT_MALLINFO_DECLARED 1
#    define MALLINFO_FIELD_TYPE size_t
struct mallinfo {
	MALLINFO_FIELD_TYPE arena;		/* non-mmapped space allocated from system */
	MALLINFO_FIELD_TYPE ordblks;	/* number of free chunks */
	MALLINFO_FIELD_TYPE smblks;		/* always 0 */
	MALLINFO_FIELD_TYPE hblks;		/* always 0 */
	MALLINFO_FIELD_TYPE hblkhd;		/* space in mmapped regions */
	MALLINFO_FIELD_TYPE usmblks;	/* maximum total allocated space */
	MALLINFO_FIELD_TYPE fsmblks;	/* always 0 */
	MALLINFO_FIELD_TYPE uordblks;	/* total allocated space */
	MALLINFO_FIELD_TYPE fordblks;	/* total free space */
	MALLINFO_FIELD_TYPE keepcost;	/* releasable (via malloc_trim) space */
};
#endif // !NO_MALLINFO && !defined(_MALLOC_H_)

namespace glf
{

/**
  mspace is an opaque type representing an independent
  region of space that supports mspace_malloc, etc.
*/
typedef void* mspace;

/**
  create_mspace creates and returns a new independent space with the
  given initial capacity, or, if 0, the default granularity size.  It
  returns null if there is no system memory available to create the
  space.  If argument locked is non-zero, the space uses a separate
  lock to control access. The capacity of the space will grow
  dynamically as needed to service mspace_malloc requests.  You can
  control the sizes of incremental increases of this space by
  compiling with a different DEFAULT_GRANULARITY or dynamically
  setting with mallopt(M_GRANULARITY, value).
*/
mspace create_mspace_with_base(void* base, size_t capacity, int locked);

/**
  destroy_mspace destroys the given space, and attempts to return all
  of its memory back to the system, returning the total number of
  bytes freed. After destruction, the results of access to all memory
  used by the space become undefined.
*/
size_t destroy_mspace(mspace);

/**
  create_mspace_with_base uses the memory supplied as the initial base
  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
  space is used for bookkeeping, so the capacity must be at least this
  large. (Otherwise 0 is returned.) When this initial space is
  exhausted, additional memory will be obtained from the system.
  Destroying this space will deallocate all additionally allocated
  space (if possible) but not the initial base.
*/
mspace create_mspace_with_base(void* base, size_t capacity, int locked);

/**
  mspace_malloc behaves as malloc, but operates within
  the given space.
*/
void* mspace_malloc(mspace, size_t);

/**
  mspace_memalign behaves as memalign, but operates within
  the given space.
*/
void* mspace_memalign(mspace, size_t align, size_t bytes);

/**
  mspace_free behaves as free, but operates within
  the given space.

  If compiled with FOOTERS==1, mspace_free is not actually needed.
  free may be called instead of mspace_free because freed chunks from
  any space are handled by their originating spaces.
*/
void mspace_free(mspace msp, void* mem);
void mspace_free2(void* mem);

#if !NO_MALLINFO && !defined(_MALLOC_H_) && !__linux && !__linux__ && !__CYGWIN__
/**
  mspace_mallinfo behaves as mallinfo, but reports properties of
  the given space.
*/
struct ::mallinfo mspace_mallinfo(mspace msp);
#endif /* NO_MALLINFO */

/**
  malloc_usable_size(void* p) behaves the same as malloc_usable_size;
*/
size_t mspace_usable_size(void* mem);

} // namespace glf

#endif
